---
title: Short-term memory
---

import AlphaCallout from '/snippets/alpha-lc-callout.mdx';

<AlphaCallout />

## Overview

Memory is a system that remembers information about previous interactions. For AI agents, memory is crucial because it lets them remember previous interactions, learn from feedback, and adapt to user preferences. As agents tackle more complex tasks with numerous user interactions, this capability becomes essential for both efficiency and user satisfaction.

Short term memory lets your application remember previous interactions within a single thread or conversation.

<Note>
    A thread organizes multiple interactions in a session, similar to the way email groups messages in a single conversation.
</Note>

Conversation history is the most common form of short-term memory. Long conversations pose a challenge to today's LLMs; a full history may not fit inside an LLM's context window, resulting in an context loss or errors.

Even if your model supports the full context length, most LLMs still perform poorly over long contexts. They get "distracted" by stale or off-topic content, all while suffering from slower response times and higher costs.

Chat models accept context using [messages](/oss/langchain/messages), which include instructions (a system message) and inputs (human messages). In chat applications, messages alternate between human inputs and model responses, resulting in a list of messages that grows longer over time. Because context windows are limited, many applications can benefit from using techniques to remove or "forget" stale information.

## Usage

To add short-term memory (thread-level persistence) to an agent, you need to specify a `checkpointer` when creating an agent.

<Info>
    LangChain's agent manages short-term memory as a part of your agent's state.

    By storing these in the graph's state, the agent can access the full context for a given conversation while maintaining separation between different threads.

    State is persisted to a database (or memory) using a checkpointer so the thread can be resumed at any time.

    Short-term memory updates when the agent is invoked or a step (like a tool call) is completed, and the state is read at the start of each step.
</Info>

:::python
```python {highlight={2,7,12}}
from langchain.agents import create_agent
from langgraph.checkpoint.memory import InMemorySaver

agent = create_agent(
    "openai:gpt-5",
    [get_user_info],
    checkpointer=InMemorySaver(),
)

agent.invoke(
    {"messages": [{"role": "user", "content": "Hi! My name is Bob."}]},
    {"configurable": {"thread_id": "1"}},
)
```
:::
:::js
```ts {highlight={2,4, 9,14}}
import { createAgent, MemorySaver } from "langchain";

const checkpointer = new MemorySaver();

const agent = createAgent({
    model: "anthropic:claude-3-7-sonnet-latest",
    tools: [],
    checkpointer,
});

await agent.invoke(
    { messages: [{ role: "user", content: "hi! i am Bob" }] },
    { configurable: { thread_id: "1" } }
);
```
:::

### In production

In production, use a checkpointer backed by a database:

:::python
```python {highlight={2,9}}
from langchain.agents import create_agent
from langgraph.checkpoint.postgres import PostgresSaver

DB_URI = "postgresql://postgres:postgres@localhost:5442/postgres?sslmode=disable"
with PostgresSaver.from_conn_string(DB_URI) as checkpointer:
    agent = create_agent(
        "openai:gpt-5",
        [get_user_info],
        checkpointer=checkpointer,
    )
```
:::
:::js
```ts
import { PostgresSaver } from "@langchain/langgraph-checkpoint-postgres";

const DB_URI = "postgresql://postgres:postgres@localhost:5442/postgres?sslmode=disable";
const checkpointer = PostgresSaver.fromConnString(DB_URI);
```
:::


## Customizing agent memory

By default, agents use `AgentState` to manage short term memory, specifically the conversation history via a `messages` key.

Users can subclass `AgentState` to add additional fields to the state.

This custom state can then be accessed via tools and dynamic prompt / model functions.

:::python
```python highlight={3-5,10}
from langchain.agents import create_agent, AgentState
from langgraph.checkpoint.memory import InMemorySaver

class CustomAgentState(AgentState):
    user_id: str

agent = create_agent(
    "openai:gpt-5",
    [get_user_info],
    state_schema=CustomAgentState,
    checkpointer=InMemorySaver(),
)
```
:::
:::js
```typescript highlight={4-7,13}
import { z } from "zod";
import { createAgent, MemorySaver } from "langchain";

const stateSchema = z.object({
    messages: z.array(z.any()),
});

const checkpointer = new MemorySaver();
const agent = createAgent({
    model: "openai:gpt-5",
    tools: [],
    stateSchema,
    checkpointer,
});
```
:::

## Common patterns

With [short-term memory](#add-short-term-memory) enabled, long conversations can exceed the LLM's context window. Common solutions are:

<CardGroup cols={2}>
    <Card title="Trim messages" icon="scissors" href="#trim-messages" arrow>
        Remove first or last N messages (before calling LLM)
    </Card>
    <Card title="Delete messages" icon="trash" href="#delete-messages" arrow>
        Delete messages from LangGraph state permanently
    </Card>
    <Card title="Summarize messages" icon="layer-group" href="#summarize-messages" arrow>
        Summarize earlier messages in the history and replace them with a summary
    </Card>
    <Card title="Custom strategies" icon="gears">
        Custom strategies (e.g., message filtering, etc.)
    </Card>
</CardGroup>

This allows the agent to keep track of the conversation without exceeding the LLM's context window.

### Trim messages

Most LLMs have a maximum supported context window (denominated in tokens).

One way to decide when to truncate messages is to count the tokens in the message history and truncate whenever it approaches that limit. If you're using LangChain, you can use the trim messages utility and specify the number of tokens to keep from the list, as well as the `strategy` (e.g., keep the last `maxTokens`) to use for handling the boundary.

:::python
To trim message history in an agent, use @[`pre_model_hook`][create_agent] with the [`trim_messages`](https://python.langchain.com/api_reference/core/messages/langchain_core.messages.utils.trim_messages.html) function:

```python
from langchain_core.messages.utils import trim_messages, count_tokens_approximately
from langchain_core.messages import BaseMessage
from langgraph.checkpoint.memory import InMemorySaver
from langchain.agents import create_agent
from langchain_core.runnables import RunnableConfig

def pre_model_hook(state) -> dict[str, list[BaseMessage]]:
    """
    This function will be called prior to every llm call to prepare the messages for the llm.
    """
    trimmed_messages = trim_messages(
        state["messages"],
        strategy="last",
        token_counter=count_tokens_approximately,
        max_tokens=384,
        start_on="human",
        end_on=("human", "tool"),
    )
    return {"llm_input_messages": trimmed_messages}


checkpointer = InMemorySaver()
agent = create_agent(
    "openai:gpt-5-nano",
    tools=[],
    pre_model_hook=pre_model_hook,
    checkpointer=checkpointer,
)

config: RunnableConfig = {"configurable": {"thread_id": "1"}}

agent.invoke({"messages": "hi, my name is bob"}, config)
agent.invoke({"messages": "write a short poem about cats"}, config)
agent.invoke({"messages": "now do the same but for dogs"}, config)
final_response = agent.invoke({"messages": "what's my name?"}, config)

final_response["messages"][-1].pretty_print()
"""
================================== Ai Message ==================================

Your name is Bob. You told me that earlier.
If you'd like me to call you a nickname or use a different name, just say the word.
"""
```
:::

:::js
To trim message history in an agent, use `stateModifier` with the [`trimMessages`](https://js.langchain.com/docs/how_to/trim_messages/) function:

```typescript
import {
    createAgent,
    trimMessages,
    MemorySaver,
    type AgentState,
} from "langchain";

// This function will be called every time before the node that calls LLM
const stateModifier = async (state: AgentState) => {
    return {
        messages: await trimMessages(state.messages, {
        strategy: "last",
        maxTokens: 384,
        startOn: "human",
        endOn: ["human", "tool"],
        tokenCounter: (msgs) => msgs.length,
        }),
    };
};

const checkpointer = new MemorySaver();
const agent = createAgent({
    model: "openai:gpt-5",
    tools: [],
    preModelHook: stateModifier,
    checkpointer,
});
```
:::

### Delete messages

You can delete messages from the graph state to manage the message history.

This is useful when you want to remove specific messages or clear the entire message history.

:::python
To delete messages from the graph state, you can use the `RemoveMessage`.

For `RemoveMessage` to work, you need to use a state key with @[`add_messages`][add_messages] [reducer](/oss/langgraph/graph-api#reducers).

The default `AgentState` provides this.

To remove specific messages:

```python {highlight={1,7}}
from langchain_core.messages import RemoveMessage

def delete_messages(state):
    messages = state["messages"]
    if len(messages) > 2:
        # remove the earliest two messages
        return {"messages": [RemoveMessage(id=m.id) for m in messages[:2]]}
```

To remove **all** messages:

```python {highlight={1,4}}
from langgraph.graph.message import REMOVE_ALL_MESSAGES

def delete_messages(state):
    return {"messages": [RemoveMessage(id=REMOVE_ALL_MESSAGES)]}
```
:::

:::js
To delete messages from the graph state, you can use the `RemoveMessage`. For `RemoveMessage` to work, you need to use a state key with @[`messagesStateReducer`][messagesStateReducer] [reducer](/oss/langgraph/graph-api#reducers), like `MessagesZodState`.

To remove specific messages:

```typescript
import { RemoveMessage } from "@langchain/core/messages";

const deleteMessages = (state) => {
    const messages = state.messages;
    if (messages.length > 2) {
        // remove the earliest two messages
        return {
        messages: messages
            .slice(0, 2)
            .map((m) => new RemoveMessage({ id: m.id })),
        };
    }
};
```
:::

<Warning>
    When deleting messages, **make sure** that the resulting message history is valid. Check the limitations of the LLM provider you're using. For example:

    * Some providers expect message history to start with a `user` message
    * Most providers require `assistant` messages with tool calls to be followed by corresponding `tool` result messages.
</Warning>

:::python

```python
from langchain_core.messages import RemoveMessage
from langchain.agents import create_agent
from langgraph.checkpoint.memory import InMemorySaver
from langchain_core.runnables import RunnableConfig


def delete_messages(state):
    messages = state["messages"]
    if len(messages) > 2:
        # remove the earliest two messages
        return {"messages": [RemoveMessage(id=m.id) for m in messages[:2]]}


agent = create_agent(
    "openai:gpt-5-nano",
    tools=[],
    prompt="Please be concise and to the point.",
    post_model_hook=delete_messages,
    checkpointer=InMemorySaver(),
)

config: RunnableConfig = {"configurable": {"thread_id": "1"}}

for event in agent.stream(
    {"messages": [{"role": "user", "content": "hi! I'm bob"}]},
    config,
    stream_mode="values",
):
    print([(message.type, message.content) for message in event["messages"]])

for event in agent.stream(
    {"messages": [{"role": "user", "content": "what's my name?"}]},
    config,
    stream_mode="values",
):
    print([(message.type, message.content) for message in event["messages"]])
```

```
[('human', "hi! I'm bob")]
[('human', "hi! I'm bob"), ('ai', 'Hi Bob! Nice to meet you. How can I help you today? I can answer questions, brainstorm ideas, draft text, explain things, or help with code.')]
[('human', "hi! I'm bob"), ('ai', 'Hi Bob! Nice to meet you. How can I help you today? I can answer questions, brainstorm ideas, draft text, explain things, or help with code.'), ('human', "what's my name?")]
[('human', "hi! I'm bob"), ('ai', 'Hi Bob! Nice to meet you. How can I help you today? I can answer questions, brainstorm ideas, draft text, explain things, or help with code.'), ('human', "what's my name?"), ('ai', 'Your name is Bob. How can I help you today, Bob?')]
[('human', "what's my name?"), ('ai', 'Your name is Bob. How can I help you today, Bob?')]
```
:::

:::js
```typescript
import { RemoveMessage } from "@langchain/core/messages";
import { AgentState, createAgent, MemorySaver } from "langchain";

const deleteMessages = (state: AgentState) => {
    const messages = state.messages;
    if (messages.length > 2) {
        // remove the earliest two messages
        return {
        messages: messages
            .slice(0, 2)
            .map((m) => new RemoveMessage({ id: m.id! })),
        };
    }
    return {};
};

const agent = createAgent({
    model: "openai:gpt-5-nano",
    tools: [],
    prompt: "Please be concise and to the point.",
    postModelHook: deleteMessages,
    checkpointer: new MemorySaver(),
});

const config = { configurable: { thread_id: "1" } };

const streamA = await agent.stream(
    { messages: [{ role: "user", content: "hi! I'm bob" }] },
    { ...config, streamMode: "values" }
);
for await (const event of streamA) {
    const messageDetails = event.messages.map((message) => [
        message.getType(),
        message.content,
    ]);
    console.log(messageDetails);
}

const streamB = await agent.stream(
    {
        messages: [{ role: "user", content: "what's my name?" }],
    },
    { ...config, streamMode: "values" }
);
for await (const event of streamB) {
    const messageDetails = event.messages.map((message) => [
        message.getType(),
        message.content,
    ]);
    console.log(messageDetails);
}
```

```
[['human', "hi! I'm bob"]]
[['human', "hi! I'm bob"], ['ai', 'Hi Bob! How are you doing today? Is there anything I can help you with?']]
[['human', "hi! I'm bob"], ['ai', 'Hi Bob! How are you doing today? Is there anything I can help you with?'], ['human', "what's my name?"]]
[['human', "hi! I'm bob"], ['ai', 'Hi Bob! How are you doing today? Is there anything I can help you with?'], ['human', "what's my name?"], ['ai', 'Your name is Bob.']]
[['human', "what's my name?"], ['ai', 'Your name is Bob.']]
```
:::

### Summarize messages

The problem with trimming or removing messages, as shown above, is that you may lose information from culling of the message queue.
Because of this, some applications benefit from a more sophisticated approach of summarizing the message history using a chat model.

![](/oss/images/summary.png)


:::python
To summarize message history in an agent, use @[`pre_model_hook`][create_agent] with a prebuilt [`SummarizationNode`](https://langchain-ai.github.io/langmem/reference/short_term/#langmem.short_term.SummarizationNode) abstraction:

{/* TODO: FIX THIS EXAMPLE, NOT ABLE TO RUN */}

```python {highlight={22,30,31}}
from langmem.short_term import SummarizationNode, RunningSummary
from langchain_core.messages.utils import count_tokens_approximately
from langchain.agents import create_agent, AgentState
from langgraph.checkpoint.memory import InMemorySaver
from langchain_openai import ChatOpenAI
from langchain_core.runnables import RunnableConfig

model = ChatOpenAI(model="gpt-4o-mini")

summarization_node = SummarizationNode(
    token_counter=count_tokens_approximately,
    model=model,
    max_tokens=384,
    max_summary_tokens=128,
    output_messages_key="llm_input_messages",
)

class State(AgentState):
    # Added for the SummarizationNode to be able to keep track of the running summary information
    context: dict[str, RunningSummary]


checkpointer = InMemorySaver()

agent = create_agent(
    model=model,
    tools=[],
    pre_model_hook=summarization_node,
    state_schema=State,
    checkpointer=checkpointer,
)

config: RunnableConfig = {"configurable": {"thread_id": "1"}}
agent.invoke({"messages": "hi, my name is bob"}, config)
agent.invoke({"messages": "write a short poem about cats"}, config)
agent.invoke({"messages": "now do the same but for dogs"}, config)
final_response = agent.invoke({"messages": "what's my name?"}, config)

print(final_response.keys())

final_response["messages"][-1].pretty_print()
print("\nSummary:", final_response["context"]["running_summary"].summary)
```
:::
:::js
TODO
:::

## Access

You can access the short-term memory of an agent in a few different ways:

* [Tools](#tools)
* [Pre model hook](#pre-model-hook)
* [Post model hook](#post-model-hook)

### Tools

#### Read short-term memory in a tool

Access short term memory (state) in a tool by injecting the agent's state into the tool signature with the `InjectedState` annotation.

This annotation hides the state from the tool signature (so the model doesn't see it), but the tool can access it.

:::python
```python
from typing import Annotated
from langchain.agents import create_agent, AgentState
from langchain.agents.tool_node import InjectedState

class CustomState(AgentState):
    user_id: str

def get_user_info(
    state: Annotated[CustomState, InjectedState]
) -> str:
    """Look up user info."""
    user_id = state["user_id"]
    return "User is John Smith" if user_id == "user_123" else "Unknown user"

agent = create_agent(
    model="openai:gpt-5-nano",
    tools=[get_user_info],
    state_schema=CustomState,
)

result = agent.invoke({
    "messages": "look up user information",
    "user_id": "user_123"
})
print(result["messages"][-1].content)
# > User is John Smith.
```
:::
:::js
```typescript
import { z } from "zod";
import { createAgent, tool } from "langchain";

const stateSchema = z.object({
    userId: z.string(),
});

const getUserInfo = tool(
    async (_, config) => {
        const userId = config.context?.userId;
        return { userId };
    },
    {
        name: "get_user_info",
        description: "Get user info",
        schema: z.object({}),
    }
);

const agent = createAgent({
    model: "openai:gpt-5-nano",
    tools: [getUserInfo],
    stateSchema,
});

const result = await agent.invoke(
    {
        messages: [{ role: "user", content: "what's my name?" }],
    },
    {
        context: {
        userId: "user_123",
        },
    }
);

console.log(result.messages.at(-1)?.content);
// Outputs: "User is John Smith."
```
:::

#### Write short-term memory from tools

To modify the agent's short-term memory (state) during execution, you can return state updates directly from the tools.

This is useful for persisting intermediate results or making information accessible to subsequent tools or prompts.

:::python
```python {highlight={10,19,20,31,40,45}}
from typing import Annotated
from langchain_core.tools import InjectedToolCallId
from langchain_core.runnables import RunnableConfig
from langchain_core.messages import ToolMessage
from langchain.agents import create_agent, AgentState
from langchain.agents.tool_node import InjectedState
from langgraph.runtime import get_runtime
from langgraph.types import Command
from pydantic import BaseModel

class CustomState(AgentState):
    user_name: str

class CustomContext(BaseModel):
    user_id: str

def update_user_info(
    tool_call_id: Annotated[str, InjectedToolCallId],
) -> Command:
    """Look up and update user info."""
    runtime = get_runtime(CustomContext)
    user_id = runtime.context.user_id
    name = "John Smith" if user_id == "user_123" else "Unknown user"
    return Command(update={
        "user_name": name,
        # update the message history
        "messages": [
            ToolMessage(
                "Successfully looked up user information",
                tool_call_id=tool_call_id
            )
        ]
    })

def greet(
    state: Annotated[CustomState, InjectedState]
) -> str:
    """Use this to greet the user once you found their info."""
    user_name = state["user_name"]
    return f"Hello {user_name}!"

agent = create_agent(
    model="openai:gpt-5-nano",
    tools=[update_user_info, greet],
    state_schema=CustomState,
    context_schema=CustomContext,
)

agent.invoke(
    {"messages": [{"role": "user", "content": "greet the user"}]},
    context=CustomContext(user_id="user_123"),
)
```
:::

:::js
```typescript
import { z } from "zod";
import { tool, createAgent } from "langchain";
import { MessagesZodState, Command } from "@langchain/langgraph";

const CustomState = z.object({
    messages: MessagesZodState.shape.messages,
    userName: z.string().optional(),
});

const updateUserInfo = tool(
    async (_, config) => {
        const userId = config.context?.userId;
        const name = userId === "user_123" ? "John Smith" : "Unknown user";
        return new Command({
        update: {
            userName: name,
            // update the message history
            messages: [
            {
                role: "tool",
                content: "Successfully looked up user information",
                tool_call_id: config.toolCall?.id,
            },
            ],
        },
        });
    },
    {
        name: "update_user_info",
        description: "Look up and update user info.",
        schema: z.object({}),
    }
);

const greet = tool(
    async (_, config) => {
        const userName = config.context?.userName;
        return `Hello ${userName}!`;
    },
    {
        name: "greet",
        description: "Use this to greet the user once you found their info.",
        schema: z.object({}),
    }
);

const agent = createAgent({
    llm: model,
    tools: [updateUserInfo, greet],
    stateSchema: CustomState,
});

await agent.invoke(
    { messages: [{ role: "user", content: "greet the user" }] },
    { context: { userId: "user_123" } }
);
```
:::

### Prompt

Access short term memory (state) in a dynamic prompt function by injecting the agent's state into the prompt function signature.

:::python
```python
from langchain_core.messages import AnyMessage
from langchain.agents import create_agent, AgentState
from langgraph.runtime import get_runtime
from typing import TypedDict


class CustomContext(TypedDict):
    user_name: str


def get_weather(city: str) -> str:
    """Get the weather in a city."""
    return f"The weather in {city} is always sunny!"


def prompt(state: AgentState) -> list[AnyMessage]:
    user_name = get_runtime(CustomContext).context["user_name"]
    system_msg = f"You are a helpful assistant. Address the user as {user_name}."
    return [{"role": "system", "content": system_msg}] + state["messages"]


agent = create_agent(
    model="openai:gpt-5-nano",
    tools=[get_weather],
    prompt=prompt,
    context_schema=CustomContext,
)

result = agent.invoke(
    {"messages": [{"role": "user", "content": "What is the weather in SF?"}]},
    context=CustomContext(user_name="John Smith"),
)
for msg in result["messages"]:
    msg.pretty_print()
```

```shell title="Output"
================================ Human Message =================================

What is the weather in SF?
================================== Ai Message ==================================
Tool Calls:
  get_weather (call_WFQlOGn4b2yoJrv7cih342FG)
 Call ID: call_WFQlOGn4b2yoJrv7cih342FG
  Args:
    city: San Francisco
================================= Tool Message =================================
Name: get_weather

The weather in San Francisco is always sunny!
================================== Ai Message ==================================

Hi John Smith, the weather in San Francisco is always sunny!
```
:::
:::js
```typescript
import { z } from "zod";
import { createAgent, tool, SystemMessage } from "langchain";

const contextSchema = z.object({
    userName: z.string(),
});

const getWeather = tool(
    async ({ city }, config) => {
        return `The weather in ${city} is always sunny!`;
    },
    {
        name: "get_weather",
        description: "Get user info",
        schema: z.object({
        city: z.string(),
        }),
    }
);

const agent = createAgent({
    model: "openai:gpt-5-nano",
    tools: [getWeather],
    contextSchema,
    prompt: (state, config) => {
        return [
        new SystemMessage(
            `You are a helpful assistant. Address the user as ${config.context?.userName}.`
        ),
        ...state.messages,
        ];
    },
});

const result = await agent.invoke(
    {
        messages: [{ role: "user", content: "What is the weather in SF?" }],
    },
    {
        context: {
        userName: "John Smith",
        },
    }
);

for (const message of result.messages) {
    console.log(message);
}
/**
 * HumanMessage {
 *   "content": "What is the weather in SF?",
 *   // ...
 * }
 * AIMessage {
 *   // ...
 *   "tool_calls": [
 *     {
 *       "name": "get_weather",
 *       "args": {
 *         "city": "San Francisco"
 *       },
 *       "type": "tool_call",
 *       "id": "call_tCidbv0apTpQpEWb3O2zQ4Yx"
 *     }
 *   ],
 *   // ...
 * }
 * ToolMessage {
 *   "content": "The weather in San Francisco is always sunny!",
 *   "tool_call_id": "call_tCidbv0apTpQpEWb3O2zQ4Yx"
 *   // ...
 * }
 * AIMessage {
 *   "content": "John Smith, here’s the latest: The weather in San Francisco is always sunny!\n\nIf you’d like more details (temperature, wind, humidity) or a forecast for the next few days, I can pull that up. What would you like?",
 *   // ...
 * }
 */
```
:::

### Pre model hook

Access short term memory (state) in a pre model hook by injecting the agent's state into the hook signature.

:::python
```python
from langchain_core.messages.utils import trim_messages, count_tokens_approximately
from langchain_core.messages import BaseMessage
from langgraph.checkpoint.memory import InMemorySaver
from langchain.agents import create_agent, AgentState


def pre_model_hook(state: AgentState) -> dict[str, list[BaseMessage]]:
    """
    This function will be called prior to every llm call to prepare the messages for the llm.
    """
    trimmed_messages = trim_messages(
        state["messages"],
        strategy="last",
        token_counter=count_tokens_approximately,
        max_tokens=384,
        start_on="human",
        end_on=("human", "tool"),
    )
    return {"llm_input_messages": trimmed_messages}

agent = create_agent(
    model="openai:gpt-5-nano",
    tools=[],
    pre_model_hook=pre_model_hook,
    checkpointer=InMemorySaver(),
)

result = agent.invoke({"messages": "hi, my name is bob"}, {"configurable": {"thread_id": "1"}})
print(result["messages"][-1].content)
```
:::
:::js
```typescript
import {
    createAgent,
    type AgentState,
    trimMessages,
    type BaseMessage,
} from "langchain";

const preModelHook = async (state: AgentState) => {
    return {
        messages: await trimMessages(state.messages, {
        maxTokens: 384,
        strategy: "last",
        startOn: "human",
        endOn: ["human", "tool"],
        tokenCounter: (msgs: BaseMessage[]) => msgs.length,
        }),
    };
};

const agent = createAgent({
    model: "openai:gpt-5-nano",
    tools: [],
    preModelHook,
});

const result = await agent.invoke(
    {
        messages: [{ role: "user", content: "hi, my name is bob" }],
    },
    {
        context: { thread_id: "1" },
    }
);
console.log(result.messages.at(-1)?.content);
```
:::

### Post model hook

Access short term memory (state) in a post model hook by injecting the agent's state into the hook signature.

:::python
```python
from langchain.agents import create_agent, AgentState

STOP_WORDS = ["password", "secret"]

def validate_response(state: AgentState) -> dict[str, list[BaseMessage]]:
    """Confirm the response doesn't have any content that is in the stop words list."""
    last_message = state["messages"][-1]
    if any(word in last_message.content for word in STOP_WORDS):
        return {"messages": [RemoveMessage(id=last_message.id)]}
    return {}

agent = create_agent(
    model="openai:gpt-5-nano",
    tools=[],
    post_model_hook=validate_response,
    checkpointer=InMemorySaver(),
)
```
:::
:::js
```typescript
import { RemoveMessage } from "@langchain/core/messages";
import { createAgent, type AgentState } from "langchain";

function validateResponse(state: AgentState) {
    const lastMessage = state.messages.at(-1)?.content;
    if (
        typeof lastMessage === "string" &&
        lastMessage.toLowerCase().includes("confidential")
    ) {
        return {
        messages: [new RemoveMessage({ id: "all" }), ...state.messages],
        };
    }
    return {};
}

const agent = createAgent({
    model: "openai:gpt-5",
    tools: [],
    postModelHook: validateResponse,
});
```
:::
